
// 作业四
// 手写实现MyPromise源码，尽可能还原每一个api，并注释思路和原理

/**
 * 首先要熟悉原生promise的使用，然后根据功能，
 * 从最小功能开始实现，然后一步步完善。
 */

// 定义promise状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise {
  // 接收一个立即执行的执行器函数，函数接收两个参数
  // resolve和reject函数参数
  constructor(executor) {
    // 捕获执行器抛出的异常
    try {
      executor(this.resolve, this.reject);
    } catch (e) {
      // 抛出异常直接reject
      this.reject(e);
    }
  }
  status = PENDING; // 默认状态pending
  value = undefined; // 缓存成功的结果
  reason = undefined; // 缓存失败的原因
  // 缓存多个成功的回调
  successCallback = [];
  // 缓存多个失败的回调
  failCallback = [];

  resolve = (value) => {
    // 只有pending状态可操作
    if (this.status !== PENDING) return;
    // 修改状态
    this.status = FULFILLED;
    // 缓存成功的值
    this.value = value;
    // 遍历成功回调，依次执行
    while (this.successCallback.length) {
      this.successCallback.shift()();
    }
  };
  reject = (reason) => {
    // 只有pending状态可操作
    if (this.status !== PENDING) return;
    // 更改状态
    this.status = REJECTED;
    // 缓存失败的原因
    this.reason = reason;
    // 遍历失败回调，依次执行
    while (this.failCallback.length) {
      this.failCallback.shift()();
    }
  };
  // 接收一个成功和一个失败回调，都是可选的
  then(successCallback, failCallback) {
    // 没传的时候，默认给一个函数，把值往下传递
    successCallback = successCallback ? successCallback : (value) => value;
    failCallback = failCallback
      ? failCallback
      : (reason) => {
        throw reason;
      };
    // 返回一个新的promise对象
    let promsie2 = new MyPromise((resolve, reject) => {
      // 判断前一个promise的状态
      if (this.status === FULFILLED) {
        // TODO 需要再理一下
        // 执行成功回调，并判断返回值类型
        setTimeout(() => {
          try {
            let result = successCallback(this.value);
            // 处理返回值
            resolvePromise(promsie2, result, resolve, reject);
          } catch (e) {
            // 捕获回调函数抛出的错误
            reject(e);
          }
        }, 0);
      } else if (this.status === REJECTED) {
        // 处理同上
        setTimeout(() => {
          try {
            let result = failCallback(this.reason);
            resolvePromise(promsie2, result, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      } else {
        // 如果是pending状态，即执行器里面是一个异步操作，就把回调收集起来，
        // 但是要用函数包装一下,并判断一下回调的执行结果,处理同上
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let result = successCallback(this.value);
              resolvePromise(promsie2, result, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let result = failCallback(this.reason);
              resolvePromise(promsie2, result, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
      }
    });
    return promsie2;
  }
  // promise执行结束(不管是否成功与否)之后会调用,接收一个回调
  finally(callback) {
    return this.then(
      (value) => {
        return MyPromise.resolve(callback()).then(() => value);
      },
      (reason) => {
        return MyPromise.resolve(callback()).then(() => {
          throw reason;
        });
      }
    );
  }
  // 错误处理
  catch(failCallback) {
    return this.then(undefined, failCallback);
  }
  static all(array) {
    // 缓存返回值
    let result = [];
    // 结束标志判断
    let index = 0;
    return new MyPromise((resolve, reject) => {
      function addData(key, value) {
        result[key] = value;
        // 结果返回的时候才会累加
        index++;
        if (index === array.length) {
          resolve(result);
        }
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          // promise 对象
          current.then(
            (value) => addData(i, value),
            (reason) => reject(reason)
          );
        } else {
          addData(i, array[i]);
        }
      }
    });
  }
  // 如果是普通值,就包装一下返回,promise的话就直接返回
  static resolve(value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise((resolve) => resolve(value));
  }
}
// promise处理函数
function resolvePromise(promsie2, result, resolve, reject) {
  // 返回的是同一个promise，就直接抛出错误，并退出
  if (promsie2 === result) {
    reject(new TypeError("循环调用了"));
    return;
  }
  // 返回的是一个promise对象，继续传递结果
  if (result instanceof MyPromise) {
    result.then(resolve, reject);
  } else {
    // 返回的是普通值，就直接调用成功
    resolve(result);
  }
}


new MyPromise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve('成功了')
    } else {
      reject('失败了')
    }
  }, 3000)
}).then(console.log).catch(console.log)